import os
import shutil
import pandas as pd
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
import time


class ImageFinderApp:
    def __init__(self, root):
        self.root = root
        self.root.title("学号图片查找工具")
        self.root.geometry("700x550")

        # 变量存储路径
        self.excel_file = tk.StringVar()
        self.search_dir = tk.StringVar()
        self.output_dir = tk.StringVar()

        # 结果存储
        self.found_files = []
        self.not_found_ids = []

        # 线程控制
        self.is_running = False
        self.progress = 0

        self.create_widgets()

    def create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # Excel文件选择
        ttk.Label(main_frame, text="1. 选择Excel文件:").grid(row=0, column=0, sticky=tk.W, pady=5)
        excel_frame = ttk.Frame(main_frame)
        excel_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        ttk.Entry(excel_frame, textvariable=self.excel_file, width=70).grid(row=0, column=0, sticky=(tk.W, tk.E))
        ttk.Button(excel_frame, text="浏览", command=self.select_excel_file).grid(row=0, column=1, padx=5)

        # 搜索目录选择
        ttk.Label(main_frame, text="2. 选择图片搜索目录:").grid(row=2, column=0, sticky=tk.W, pady=5)
        search_frame = ttk.Frame(main_frame)
        search_frame.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        ttk.Entry(search_frame, textvariable=self.search_dir, width=70).grid(row=0, column=0, sticky=(tk.W, tk.E))
        ttk.Button(search_frame, text="浏览", command=self.select_search_dir).grid(row=0, column=1, padx=5)

        # 输出目录选择
        ttk.Label(main_frame, text="3. 选择图片输出目录:").grid(row=4, column=0, sticky=tk.W, pady=5)
        output_frame = ttk.Frame(main_frame)
        output_frame.grid(row=5, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
        ttk.Entry(output_frame, textvariable=self.output_dir, width=70).grid(row=0, column=0, sticky=(tk.W, tk.E))
        ttk.Button(output_frame, text="浏览", command=self.select_output_dir).grid(row=0, column=1, padx=5)

        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=6, column=0, columnspan=2, pady=20)

        self.start_button = ttk.Button(button_frame, text="开始查找并复制图片", command=self.start_find_and_copy)
        self.start_button.grid(row=0, column=0, padx=10)
        ttk.Button(button_frame, text="导出查找结果", command=self.export_results).grid(row=0, column=1, padx=10)
        self.stop_button = ttk.Button(button_frame, text="停止", command=self.stop_search, state=tk.DISABLED)
        self.stop_button.grid(row=0, column=2, padx=10)

        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(main_frame, variable=self.progress_var, maximum=100)
        self.progress_bar.grid(row=7, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=10)

        # 状态标签
        self.status_label = ttk.Label(main_frame, text="准备就绪")
        self.status_label.grid(row=8, column=0, columnspan=2, pady=5)

        # 当前目录显示
        ttk.Label(main_frame, text="当前搜索目录:").grid(row=9, column=0, sticky=tk.W, pady=5)
        self.current_dir_var = tk.StringVar(value="未开始")
        current_dir_label = ttk.Label(main_frame, textvariable=self.current_dir_var, foreground="blue")
        current_dir_label.grid(row=10, column=0, columnspan=2, sticky=tk.W, pady=2)

        # 统计信息
        stats_frame = ttk.Frame(main_frame)
        stats_frame.grid(row=11, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)

        self.scanned_dirs_var = tk.StringVar(value="已扫描目录: 0")
        ttk.Label(stats_frame, textvariable=self.scanned_dirs_var).grid(row=0, column=0, sticky=tk.W, padx=(0, 20))

        self.scanned_files_var = tk.StringVar(value="已扫描文件: 0")
        ttk.Label(stats_frame, textvariable=self.scanned_files_var).grid(row=0, column=1, sticky=tk.W, padx=(0, 20))

        self.found_jpgs_var = tk.StringVar(value="找到图片: 0")
        ttk.Label(stats_frame, textvariable=self.found_jpgs_var).grid(row=0, column=2, sticky=tk.W)

        # 结果显示区域
        ttk.Label(main_frame, text="查找结果:").grid(row=12, column=0, sticky=tk.W, pady=5)
        self.result_text = tk.Text(main_frame, height=12, width=80)
        self.result_text.grid(row=13, column=0, columnspan=2, pady=5, sticky=(tk.W, tk.E))

        # 滚动条
        scrollbar = ttk.Scrollbar(main_frame, orient="vertical", command=self.result_text.yview)
        scrollbar.grid(row=13, column=2, sticky=(tk.N, tk.S))
        self.result_text.configure(yscrollcommand=scrollbar.set)

        # 配置网格权重
        main_frame.columnconfigure(0, weight=1)
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)

    def select_excel_file(self):
        filename = filedialog.askopenfilename(
            title="选择Excel文件",
            filetypes=[("Excel files", "*.xlsx *.xls"), ("All files", "*.*")]
        )
        if filename:
            self.excel_file.set(filename)

    def select_search_dir(self):
        directory = filedialog.askdirectory(title="选择图片搜索目录")
        if directory:
            self.search_dir.set(directory)

    def select_output_dir(self):
        directory = filedialog.askdirectory(title="选择图片输出目录")
        if directory:
            self.output_dir.set(directory)

    def update_status(self, message, progress=None):
        """更新状态标签和进度条"""
        self.status_label.config(text=message)
        if progress is not None:
            self.progress_var.set(progress)
        self.root.update_idletasks()

    def update_current_dir(self, directory):
        """更新当前搜索目录显示"""
        # 缩短过长的路径显示
        if len(directory) > 80:
            display_dir = "..." + directory[-77:]
        else:
            display_dir = directory
        self.current_dir_var.set(display_dir)
        self.root.update_idletasks()

    def update_stats(self, scanned_dirs=0, scanned_files=0, found_imgs=0):
        """更新统计信息"""
        self.scanned_dirs_var.set(f"已扫描目录: {scanned_dirs}")
        self.scanned_files_var.set(f"已扫描文件: {scanned_files}")
        self.found_jpgs_var.set(f"找到图片: {found_imgs}")
        self.root.update_idletasks()

    def start_find_and_copy(self):
        """开始查找和复制过程（在新线程中）"""
        if not self.excel_file.get():
            messagebox.showerror("错误", "请选择Excel文件")
            return
        if not self.search_dir.get():
            messagebox.showerror("错误", "请选择图片搜索目录")
            return
        if not self.output_dir.get():
            messagebox.showerror("错误", "请选择图片输出目录")
            return

        # 禁用开始按钮，启用停止按钮
        self.start_button.config(state=tk.DISABLED)
        self.stop_button.config(state=tk.NORMAL)
        self.is_running = True

        # 重置统计信息
        self.update_stats(0, 0, 0)
        self.current_dir_var.set("未开始")

        # 清空结果区域
        self.result_text.delete(1.0, tk.END)

        # 在新线程中执行查找和复制
        thread = threading.Thread(target=self.find_and_copy_images)
        thread.daemon = True
        thread.start()

    def stop_search(self):
        """停止搜索过程"""
        self.is_running = False
        self.start_button.config(state=tk.NORMAL)
        self.stop_button.config(state=tk.DISABLED)
        self.update_status("搜索已停止")

    def find_image_files(self, directory):
        """递归查找目录中的所有图片文件（支持.jpg和.jpeg），包括最深层的子目录"""
        image_files = {}
        scanned_dirs = 0
        scanned_files = 0
        found_imgs = 0

        # 使用os.walk递归遍历所有子目录
        for root_dir, dirs, files in os.walk(directory):
            # 检查是否应该停止
            if not self.is_running:
                return image_files, scanned_dirs, scanned_files, found_imgs

            # 更新当前目录显示
            self.update_current_dir(root_dir)

            scanned_dirs += 1
            scanned_files += len(files)

            for file in files:
                # 检查文件是否为图片格式（.jpg或.jpeg）
                if file.lower().endswith(('.jpg', '.jpeg')):
                    file_path = os.path.join(root_dir, file)
                    # 存储文件名（不含扩展名）和完整路径的映射
                    file_name_without_ext = os.path.splitext(file)[0]
                    image_files[file_name_without_ext] = file_path
                    found_imgs += 1

            # 每扫描10个目录更新一次统计信息
            if scanned_dirs % 10 == 0:
                self.update_stats(scanned_dirs, scanned_files, found_imgs)

        return image_files, scanned_dirs, scanned_files, found_imgs

    def find_and_copy_images(self):
        try:
            # 读取Excel文件
            df = pd.read_excel(self.excel_file.get())

            # 假设学号在第一列，身份证号在第二列，跳过标题行
            student_data = []
            for i in range(1, len(df)):
                student_id = str(df.iloc[i, 0])
                id_card = str(df.iloc[i, 1])
                student_data.append({
                    '学号': student_id,
                    '身份证': id_card
                })

            # 清空之前的结果
            self.found_files = []
            self.not_found_ids = []

            # 确保输出目录存在
            os.makedirs(self.output_dir.get(), exist_ok=True)

            # 更新状态
            self.update_status("正在搜索图片文件...", 0)

            # 查找所有图片文件（包括所有子目录）
            start_time = time.time()
            image_files, scanned_dirs, scanned_files, found_imgs = self.find_image_files(self.search_dir.get())
            search_time = time.time() - start_time

            # 更新最终统计信息
            self.update_stats(scanned_dirs, scanned_files, found_imgs)
            self.update_status(f"搜索完成，共找到 {found_imgs} 个图片文件，耗时 {search_time:.2f} 秒", 50)

            # 查找并复制图片
            self.update_status("开始匹配学号并复制图片...", 50)

            found_count = 0
            total_students = len(student_data)

            for i, student in enumerate(student_data):
                # 检查是否应该停止
                if not self.is_running:
                    self.update_status("搜索已停止")
                    return

                student_id = student['学号']
                id_card = student['身份证']

                # 先尝试按学号查找
                if student_id in image_files:
                    # 复制图片到输出目录，命名为学号.jpg
                    source_path = image_files[student_id]
                    dest_path = os.path.join(self.output_dir.get(), f"{student_id}.jpg")
                    shutil.copy2(source_path, dest_path)
                    self.found_files.append({
                        '学号': student_id,
                        '身份证': id_card,
                        '文件名': f"{student_id}.jpg",
                        '原路径': source_path,
                        '查找方式': '学号'
                    })
                    found_count += 1
                # 如果按学号没找到，尝试按身份证号查找
                elif id_card in image_files:
                    # 复制图片到输出目录，命名为学号.jpg
                    source_path = image_files[id_card]
                    dest_path = os.path.join(self.output_dir.get(), f"{student_id}.jpg")
                    shutil.copy2(source_path, dest_path)
                    self.found_files.append({
                        '学号': student_id,
                        '身份证': id_card,
                        '文件名': f"{student_id}.jpg",
                        '原路径': source_path,
                        '查找方式': '身份证'
                    })
                    found_count += 1
                else:
                    # 两种方式都没找到
                    self.not_found_ids.append({
                        '学号': student_id,
                        '身份证': id_card
                    })

                # 更新进度
                if i % 10 == 0 or i == total_students - 1:
                    progress = 50 + (i / total_students) * 50
                    self.update_status(f"已处理 {i + 1}/{total_students} 个学生，找到 {found_count} 张图片", progress)

            # 显示结果
            self.result_text.insert(tk.END, f"查找完成！\n")
            self.result_text.insert(tk.END, f"总共处理学生数量: {total_students}\n")
            self.result_text.insert(tk.END, f"找到并复制的图片数量: {found_count}\n")
            self.result_text.insert(tk.END, f"未找到的学生数量: {len(self.not_found_ids)}\n")
            self.result_text.insert(tk.END, f"搜索耗时: {search_time:.2f} 秒\n\n")

            # 显示通过不同方式找到的图片数量
            found_by_student_id = len([f for f in self.found_files if f['查找方式'] == '学号'])
            found_by_id_card = len([f for f in self.found_files if f['查找方式'] == '身份证'])
            self.result_text.insert(tk.END, f"按学号找到: {found_by_student_id} 张\n")
            self.result_text.insert(tk.END, f"按身份证找到: {found_by_id_card} 张\n\n")

            if self.not_found_ids:
                self.result_text.insert(tk.END, "未找到图片的学生:\n")
                for student in self.not_found_ids:
                    self.result_text.insert(tk.END, f"学号: {student['学号']}, 身份证: {student['身份证']}\n")

            self.update_status(f"完成！找到 {found_count} 张图片，未找到 {len(self.not_found_ids)} 张", 100)
            messagebox.showinfo("完成",
                                f"图片查找和复制完成！\n找到 {found_count} 张图片，未找到 {len(self.not_found_ids)} 张")

        except Exception as e:
            self.update_status(f"错误: {str(e)}")
            messagebox.showerror("错误", f"处理过程中出现错误:\n{str(e)}")
        finally:
            # 恢复按钮状态
            self.start_button.config(state=tk.NORMAL)
            self.stop_button.config(state=tk.DISABLED)
            self.is_running = False

    def export_results(self):
        if not self.found_files and not self.not_found_ids:
            messagebox.showwarning("警告", "请先执行查找操作")
            return

        try:
            # 创建结果DataFrame
            result_data = []
            for item in self.found_files:
                result_data.append({
                    "学号": item['学号'],
                    "身份证": item['身份证'],
                    "是否找到": "是",
                    "查找方式": item['查找方式'],
                    "文件名": item['文件名'],
                    "原路径": item['原路径']
                })
            for student in self.not_found_ids:
                result_data.append({
                    "学号": student['学号'],
                    "身份证": student['身份证'],
                    "是否找到": "否",
                    "查找方式": "",
                    "文件名": "",
                    "原路径": ""
                })

            df_result = pd.DataFrame(result_data)

            # 选择保存路径
            output_file = filedialog.asksaveasfilename(
                title="保存查找结果",
                defaultextension=".xlsx",
                filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")]
            )

            if output_file:
                df_result.to_excel(output_file, index=False)
                messagebox.showinfo("成功", f"查找结果已导出到:\n{output_file}")

        except Exception as e:
            messagebox.showerror("错误", f"导出过程中出现错误:\n{str(e)}")


def main():
    root = tk.Tk()
    app = ImageFinderApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()